import { execSync, spawn } from 'child_process';
import { Logger } from './logger.js';

const logger = new Logger('');

/**
 * 同步执行命令
 * @param {string} command - 要执行的命令
 * @param {Object} options - 执行选项
 * @param {boolean} options.silent - 是否静默执行
 * @param {boolean} options.ignoreError - 是否忽略错误
 * @param {string} options.cwd - 工作目录
 * @returns {string|null} 命令输出或 null
 */
function exec(command, options = {}) {
  const defaultOptions = {
    encoding: 'utf8',
    stdio: options.silent ? 'pipe' : 'inherit',
    windowsHide: true,
  };

  try {
    const result = execSync(command, { ...defaultOptions, ...options });
    return options.silent ? result?.trim() : result;
  } catch (error) {
    if (!options.ignoreError) {
      logger.error(`Command failed: ${command}`);
      logger.error(error.message);
      throw error;
    }
    return null;
  }
}

/**
 * 异步执行命令
 * @param {string} command - 命令
 * @param {string[]} args - 参数
 * @param {Object} options - 选项
 * @returns {Promise<{code: number, stdout: string, stderr: string}>}
 */
async function execAsync(command, args = [], options = {}) {
  return new Promise((resolve, reject) => {
    const child = spawn(command, args, {
      stdio: options.silent ? 'pipe' : 'inherit',
      windowsHide: true,
      ...options,
    });

    let stdout = '';
    let stderr = '';

    if (options.silent) {
      child.stdout?.on('data', (data) => {
        stdout += data.toString();
      });
      child.stderr?.on('data', (data) => {
        stderr += data.toString();
      });
    }

    child.on('close', (code) => {
      if (code === 0) {
        resolve({ code, stdout, stderr });
      } else {
        reject(new Error(`Command failed with code ${code}: ${stderr}`));
      }
    });

    child.on('error', (err) => {
      reject(new Error(`Failed to start command: ${err.message}`));
    });
  });
}

/**
 * 执行 Node 脚本
 * @param {string} scriptPath - 脚本路径
 * @param {string[]} args - 参数
 */
function execNodeScript(scriptPath, args = []) {
  return new Promise((resolve, reject) => {
    const child = spawn('node', [scriptPath, ...args], {
      stdio: 'inherit',
    });

    child.on('exit', (code) => {
      if (code === 0) {
        resolve(code);
      } else {
        reject(new Error(`Script exited with code ${code}`));
      }
    });

    child.on('error', (err) => {
      reject(new Error(`Failed to start command: ${err.message}`));
    });
  });
}

export { exec, execAsync, execNodeScript };
